using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;


namespace XLFrame.NodeEditor
{
    /// <summary>
    /// 节点样式基类 支持初始化生命周期,有专属数据存储空间和端口管理,适合需要加载和保存有变化的样式
    /// 约定 所有子类使用NodeStyle结尾
    /// 生命周期
    /// OnNodeStyleInit
    /// OnIsNewNode | OnIsNotNewNode
    /// </summary>
    public abstract class NodeStyleBase : VisualElement,INodeStyleInit
    {
        /// <summary>
        /// 节点视图引用
        /// </summary>
        public NodeViewBase NodeView { get; private set; }
        
        /// <summary>
        /// 保存的数据,包含样式自定义数据
        /// </summary>
        public NodeStyleData StyleData { get; private set; }

        /// <summary>
        /// 所有端口包含输入和输出[GUID,Port] 由加载时自动填充,需要手动放置到对应容器中
        /// </summary>
        public Dictionary<string, Port> Ports { get; private set; } = new Dictionary<string, Port>();

        protected bool IsNewNode => NodeView.IsNewNode;

        /// <summary>
        /// 添加样式时初始化
        /// </summary>
        /// <param name="nodeViewBase"></param>
        void INodeStyleInit.AddStyleInit(NodeViewBase nodeViewBase)
        {
            NodeView = nodeViewBase;
            OnNodeStyleInit();
            if (IsNewNode)
            {
                OnIsNewNode();
            }
            else
            {                
                OnIsNotNewNode();
            }
        }

        /// <summary>
        /// 子集重写用来编写样式,首次调用
        /// </summary>
        protected abstract void OnNodeStyleInit();

        /// <summary>
        /// 是新建立的节点,此处创建Port
        /// </summary>
        protected virtual void OnIsNewNode()
        {
            
        }
        /// <summary>
        /// 是加载存档的节点,需要你恢复Port的位置 数据位于Ports
        /// </summary>
        protected virtual void OnIsNotNewNode()
        {
            
        }
        

        /// <summary>
        /// 创建一个输出端口,端口名称和显示名为portName
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="portName"></param>
        /// <param name="capacity"></param>
        /// <returns></returns>
        public Port CreateOutputPort<T>(string portName,Port.Capacity capacity = Port.Capacity.Multi)
        {
           var port = NodeView.NodePort.CreatePortForNode(typeof(T), portName, Guid.NewGuid().ToString(),false,capacity,
                                                true,false,StyleData.StyleTypeID);
           return port;
        }

        /// <summary>
        /// 创建一个输入端口,端口名称和显示名为portName
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="portName"></param>
        /// <param name="capacity"></param>
        /// <returns></returns>
        public Port CreateInputPort<T>(string portName, Port.Capacity capacity = Port.Capacity.Single)
        {
            var port = NodeView.NodePort.CreatePortForNode(typeof(T), portName, Guid.NewGuid().ToString(),true,capacity,
                                                           true,false,StyleData.StyleTypeID);
            return port;
        }
        
        /// <summary>
        /// 创建一个新的样式类
        /// </summary>
        /// <param name="container"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static NodeStyleBase CreateNodeStyle<T>(NodeStyleData.NodeStyleContainer container = NodeStyleData.NodeStyleContainer.extensionContainer) where T : NodeStyleBase, new()
        {
            var data = NodeStyleData.CreateNodeStyleData(typeof(T),container);
            var style = new T();
            style.StyleData = data;
            return style;
        }
        
        /// <summary>
        /// 通过数据创建样式实例
        /// </summary>
        /// <param name="styleData"></param>
        /// <returns></returns>
        public static NodeStyleBase CreateNodeStyle(NodeStyleData styleData)
        {
            var type = System.Type.GetType(styleData.TypeName);
            if (type is null) return default;
            var style = System.Activator.CreateInstance(type) as NodeStyleBase;
            style.StyleData = styleData;
            return style;
        }
    }

    /// <summary>
    /// 负责初始化样式
    /// </summary>
    public interface INodeStyleInit
    {
        /// <summary>
        /// 添加样式时初始化
        /// </summary>
        /// <param name="nodeViewBase"></param>
        void AddStyleInit(NodeViewBase nodeViewBase);
    }
}
